﻿using System;
using System.Linq;
using SGS.Standard;
using SGS.Standard.Actor;
using System.Collections.Generic;
using SGS.Standard.EventArgs;
using SGS.Standard.Delegate;
using SGS.Cards;
using SGS.Standard.CardSelector;

namespace GameLoader
{
    public class ConsoleGame
    {
        GameContext g = new GameContext();

        public void Do()
        {
            g.OnNoticeMessage += new NoticeMessageEventHandler((sender, msg) =>
            {
                Console.WriteLine(msg);
            });

            g.OnHunanActor += new HumanActorEventHandler((sender, eq, ea) =>
            {
                Console.WriteLine( "{0} Human Actor: {1}", eq.AnswerPlayer.PlayerName, eq.SourceActor == null ? "" : eq.SourceActor.GetType().FullName );
                Console.WriteLine( "Your HP {0}/{1}: , Your Card is: ", eq.AnswerPlayer.GameInfo.CurrentHP, eq.AnswerPlayer.GameInfo.MaxHP );
                foreach (var c in eq.AnswerPlayer.GameInfo.OwnCards)
                {
                    Console.WriteLine( "___" + c.ToString() );
                }

                // 特殊处理，
                if (eq.SourceActor is SelectOtherCardsActor)
                {
                    Console.WriteLine( "选牌事件预览" );
                    foreach (var item in (eq.SourceActor as SelectOtherCardsActor).HiddenCardMapping.MappingResult)
                    {
                        Console.WriteLine( "--" + item.ToString() );
                    }
                }
                
                bool r = false;
                while (true)
                {
                    try
                    {
                        string str = Console.ReadLine().ToLower();
                        string[] args = str.Split( ' ' );
                        switch (args[0])
                        {
                            case "query":
                                r = OnQueryCommand( sender, eq, ea, args );
                                break;
                            case "game":
                                r = OnGameCommand( sender, eq, ea, args );
                                break;
                            case "cancel":
                                return;
                            case "god":
                                r = OnGodCommand(sender, eq, ea, args);
                                break;
                            case "test":
                                r = OnTestCommand( sender, eq, ea, args );
                                break;
                        }
                    }
                    catch(Exception ex)
                    {
                        g.RaiseNoticeMessageEvent( ex.ToString() );
                        r = false;
                    }

                    if (r)
                    {
                        break;
                    }
                }
            });

            PlayerCollection pc = new PlayerCollection();
            pc.Add(new Player("大一"));
            pc.Add(new Player("小二"));
            pc.Add(new Player("张三"));
            pc.Add(new Player("李四"));
            pc.Add(new Player("王五"));
            pc.Add(new Player("朱六"));
            pc.Add(new Player("黄七"));
            pc.Add(new Player("赵八"));

            g.PlayersCircle = pc;

            g.Start();
        }

        private bool OnTestCommand( object sender, HumanActorEventArgs eq, HumanAnswerActorEventArgs ea, string[] args )
        {
            Player player = null;
            string cmd = args.Length >= 2 ? args[1] : "help";

            switch (cmd.ToLower())
            {
                case "help":
                    Console.WriteLine("=====================================");
                    Console.WriteLine("test help command:");
                    Console.WriteLine( "test do []" );
                    Console.WriteLine( "=====================================" );
                    break;
                case "do":
                    if (!GetPlayerByNumber(eq.GameContext.PlayersCircle, eq.AnswerPlayer, args.Length >= 3 ? args[2] : "", out player))
                    {
                        break;
                    }

                    CardSelectorMapping mapping = new CardSelectorMapping( player );
                    break;
            }

            return false;
        }

        private bool OnGodCommand(object sender, HumanActorEventArgs eq, HumanAnswerActorEventArgs ea, string[] args)
        {
            Player player = null;
            string cmd = args.Length >= 2 ? args[1] : "help";

            switch (cmd.ToLower())
            {
                case "help":
                    Console.WriteLine("=====================================");
                    Console.WriteLine("god help command:");
                    Console.WriteLine("god allhplost");
                    Console.WriteLine("god allhpheal");
                    Console.WriteLine("god hpdown [player number]");
                    Console.WriteLine("god hpup [player number]");
                    Console.WriteLine( "god createcard (CardType) [player number]" );
                    Console.WriteLine("=====================================");
                    return false;
                    // break;
                case "allhplost":
                    foreach (var p in eq.GameContext.PlayersCircle)
                    {
                        SGS.Standard.GameLogic.Core.GL_Damage(null, p, DamageType.Lost, null );
                    }
                    return false;
                    // break;
                case "allhpheal":
                    foreach (var p in eq.GameContext.PlayersCircle)
                    {
                        SGS.Standard.GameLogic.Core.GL_Heal(null, p);
                    }
                    return false;
                case "hpdown":
                    if (!GetPlayerByNumber(eq.GameContext.PlayersCircle, eq.AnswerPlayer, args.Length >= 3 ? args[2] : "", out player))
                    {
                        break;
                    }
                    player.GameInfo.CurrentHP--;
                    break;
                case "hpup":
                    if (!GetPlayerByNumber(eq.GameContext.PlayersCircle, eq.AnswerPlayer, args.Length >= 3 ? args[2] : "", out player))
                    {
                        break;
                    }
                    player.GameInfo.CurrentHP++;
                    break;
                case "createcard":
                    if (!GetPlayerByNumber(eq.GameContext.PlayersCircle, eq.AnswerPlayer, args.Length >= 4 ? args[3] : "", out player))
                    {
                        break;
                    }
                    string args3 = args.Length > 4 ? args[3] : "None";
                    player.GameInfo.OwnCards.PushToEnd(new Card( Suit.None, 9999, (CardType)Enum.Parse(typeof(CardType), args[2], true)).AsList());
                    break;
            }
            return false;
        }

        private bool OnGameCommand(object sender, HumanActorEventArgs eq, HumanAnswerActorEventArgs ea, string[] args)
        {
            string cmd = args.Length >= 2 ? args[1] : "help";

            switch (cmd.ToLower())
            {
                case "help":
                    Console.WriteLine( "=====================================" );
                    Console.WriteLine( "game help command:" );
                    Console.WriteLine( "game cancel" );
                    Console.WriteLine( "game skip" );
                    Console.WriteLine( "game usecard (cardids) (firsttargets) (secondtargets)" );
                    Console.WriteLine("game discardstage (cardids)");
                    Console.WriteLine( "=====================================" );
                    break;
                case "cancel":
                    ea.AnswerActor = new CancelActor();
                    return true;
                case "skip":
                    ea.AnswerActor = new SkipActor();
                    return true;
                case "selectcard":
                    // TODO
                    if (args.Length < 3)
                    {
                        return false;
                    }
                    
                    int mappingItemId = Convert.ToInt32( args[2] );
                    if ((eq.SourceActor as SelectOtherCardsActor).HiddenCardMapping.MappingResult.Where( p => p.UniqueID == mappingItemId ).Count() == 0)
                    {
                        Console.WriteLine( "选定的卡牌不存在" );
                    }
                    else
                    {
                        ea.AnswerActor = new SGS.Standard.Actor.HumanAnswerActor.SelectOtherCardsAnswerActor( mappingItemId );
                        return true;
                    }
                    // useCards = eq.GameContext.CardHeap.AllCards.Where( p => cardIds.Contains( p.UniqueID ) ).ToList();
                    // useCards = eq.AnswerPlayer.GameInfo.OwnCards.Where( p => cardIds.Contains( p.UniqueID ) ).ToList(); // eq.GameContext.CardHeap.AllCards.Where(p => cardIds.Contains(p.UniqueID)).ToList();
                    
                    break;
                case "usecard":
                    // TODO
                    if (args.Length == 2)
                    {
                        return false;
                    }

                    List<Card> useCards = new List<Card>();
                    List<Player> firstTargets = new List<Player>();
                    List<Player> secondTargets = new List<Player>();

                    if (args.Length >= 3)
                    {
                        List<int> cardIds = SGS.Utility.Common.ArrayConvert( args[2].Split( ',' ) );
                        // useCards = eq.GameContext.CardHeap.AllCards.Where( p => cardIds.Contains( p.UniqueID ) ).ToList();
                        useCards = eq.AnswerPlayer.GameInfo.OwnCards.Where(p => cardIds.Contains(p.UniqueID)).ToList(); // eq.GameContext.CardHeap.AllCards.Where(p => cardIds.Contains(p.UniqueID)).ToList();
                    }

                    if (args.Length >= 4)
                    {
                        List<int> playerIds = SGS.Utility.Common.ArrayConvert( args[3].Split( ',' ) );
                        firstTargets = eq.GameContext.PlayersCircle.Where(p => playerIds.Contains(p.GameInfo.Number)).ToList();
                    }

                    if (args.Length >= 5)
                    {
                        List<int> playerIds = SGS.Utility.Common.ArrayConvert( args[4].Split( ',' ) );
                        secondTargets = eq.GameContext.PlayersCircle.Where(p => playerIds.Contains(p.GameInfo.Number)).ToList();
                    }

                    var usecardAnswer = new SGS.Standard.Actor.HumanAnswerActor.UseCardActor() 
                    { 
                        ActorPlayer = eq.AnswerPlayer,
                        UsedCards = useCards, 
                        TargetFirst = firstTargets, 
                        TargetSecond = secondTargets 
                    };
                    
                    ea.AnswerActor = usecardAnswer;

                    return true;
                case "discardstage":
                    string[] cardIDs = (args.Length >= 3 ? args[2] : "").Split( ',' );
                    if (cardIDs.Length == 1 && string.IsNullOrEmpty( cardIDs[0] ))
                    {
                        cardIDs = new string[0];
                    }

                    List<int> listCardUids = SGS.Utility.Common.ArrayConvert( cardIDs );

                    var query = from card in eq.AnswerPlayer.GameInfo.OwnCards
                                from uid in listCardUids
                                where card.UniqueID == uid
                                select card;

                    ea.AnswerActor = new DiscardStageHumanAnswerActor( query );
                    return true;
            }

            return false;
        }

        public bool OnQueryCommand(object sender, HumanActorEventArgs eq, HumanAnswerActorEventArgs ea, string[] args)
        {
            Player player = null;

            string cmd = args.Length >= 2 ? args[1] : "help";
            switch (cmd.ToLower())
            {
                case "help":
                    Console.WriteLine("=====================================");
                    Console.WriteLine("query help command:");
                    Console.WriteLine("query owncard [player number]");
                    Console.WriteLine("query gameinfo [player number]");
                    Console.WriteLine("query discardheap[card count]");
                    Console.WriteLine("query cardheap [card count]");
                    Console.WriteLine("query distance");
                    Console.WriteLine("=====================================");
                    break;
                case "owncard":
                    if (!GetPlayerByNumber(eq.GameContext.PlayersCircle, eq.AnswerPlayer, args.Length >= 3 ? args[2] : "", out player))
                    {
                        break;
                    }
                    Console.WriteLine("player {0} {1} has cards:", player.Name, player.GameInfo.SelectedCharacter.Name);
                    foreach (var o in player.GameInfo.OwnCards)
                    {
                        Console.WriteLine(o.ToString());
                    }
                    break;
                case "gameinfo":
                    if (!GetPlayerByNumber(eq.GameContext.PlayersCircle, eq.AnswerPlayer, args.Length >= 3 ? args[2] : "", out player))
                    {
                        break;
                    }
                    var gameinfo = player.GameInfo;
                    Console.WriteLine("player {0} {1} Game Info:", player.Name, player.GameInfo.SelectedCharacter.Name);
                    Console.WriteLine("Blood : {0} / {1}", gameinfo.CurrentHP, gameinfo.MaxHP);
                    Console.WriteLine("Character : {0}", gameinfo.SelectedCharacter.Name);
                    Console.WriteLine("Skill : {0}", string.Join(", ", gameinfo.SelectedCharacter.Skills.Select(p => p.ActocName).ToList()));
                    Console.WriteLine("JudgeArea: ", string.Join(",", gameinfo.JudgeArea.Select(p=>p.AsSkillType.ToString()).ToArray() ));
                    Console.WriteLine( "Equipment: {0},{1},{2},{3}", gameinfo.Weapon, gameinfo.Armor, gameinfo.AttackHorse, gameinfo.DefenseHorse );
                    break;
                case "cardheap":
                    int cardHeapCount = Convert.ToInt32( (args.Length >= 3 ? args[2] : null) ?? "5" );
                    var list = eq.GameContext.CardHeap.CardsHeap.ToList();
                    // list.Reverse();
                    var cardHeapTopNCard = list.Take( cardHeapCount );
                    Console.WriteLine( "System Card heap : {0} / {1}", cardHeapCount, ea.GameContext.CardHeap.CardsHeap.Count );
                    
                    foreach (var c in cardHeapTopNCard)
                    {
                        Console.WriteLine( c.ToString() );
                    }
                    break;
                case "discardheap":
                    int discardHeapCount = Convert.ToInt32( (args.Length >= 3 ? args[2] : null) ?? "5" );
                    var list2 = eq.GameContext.CardHeap.DiscardsHeap.ToList();
                    list2.Reverse();
                    var discardHeapTopNCard = list2.Take(discardHeapCount);
                    Console.WriteLine( "Discard heap : {0} / {1}", discardHeapCount, ea.GameContext.CardHeap.DiscardsHeap.Count );
                    foreach (var c in discardHeapTopNCard)
                    {
                        Console.WriteLine( c.ToString() );
                    }
                    break;
                case "distance":
                    var distanceCollection = PlayerDistanceCollection.Calc(eq.GameContext.PlayersCircle, eq.AnswerPlayer);
                    foreach (var distance in distanceCollection)
                    {
                        Console.WriteLine( "To {0} Distance = {1}", distance.To.PlayerName, distance.Distance );
                    }
                    break;
            }

            return false;
        }

        private static bool GetPlayerByNumber(PlayerCollection pc, Player currentPlayer, string playerNumber, out Player targetPlayer)
        {
            int dummy = -1;
            if (!int.TryParse(playerNumber, out dummy))
            {
                dummy = -1;
            }
            
            if (dummy == -1)
            {
                targetPlayer = currentPlayer;
            }
            else
            {
                targetPlayer = pc.Where(p => p.GameInfo.Number == dummy).FirstOrDefault();
                if (targetPlayer == null)
                {
                    Console.WriteLine("player {0} is not exists", dummy);
                    return false;
                }
            }

            return true;
        }
    }
}
